package org.njyinghuo.sdk.bytedance.client.douyin;

import cn.hutool.core.io.FileUtil;
import cn.hutool.log.Log;
import cn.hutool.log.LogFactory;
import org.njyinghuo.sdk.bytedance.conf.DouYingScope;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.util.Arrays;
import java.util.Base64;
import java.util.List;
import java.util.Map;

public class DouyinClient {
    private String clientKey, clientSecret, access_token, open_id, refresh_token;
    private static final Log log = LogFactory.get();

    public DouyinClient(String clientKey, String clientSecret) {
        this.clientKey = clientKey;
        this.clientSecret = clientSecret;
    }

    /**
     * 生成授权链接,获取授权码
     *
     * @param scopeList   应用授权作用域
     * @param redirectUri 授权成功后的回调地址，必须以http/https开头。域名必须对应申请应用时填写的域名，如不清楚请联系应用申请人。
     * @return
     */
    public String OauthConnect(List<DouYingScope> scopeList, String redirectUri) {
        return OauthConnect(scopeList, redirectUri, null, "");
    }

    /**
     * 生成授权链接,获取授权码
     *
     * @param scopeList     应用授权作用域
     * @param redirectUri   授权成功后的回调地址，必须以http/https开头。域名必须对应申请应用时填写的域名，如不清楚请联系应用申请人。
     * @param optionalScope 应用授权可选作用域,多个授权作用域以英文逗号（,）分隔，每一个授权作用域后需要加上一个是否默认勾选的参数，1为默认勾选，0为默认不勾选
     * @return
     */
    public String OauthConnect(List<DouYingScope> scopeList, String redirectUri, Map<DouYingScope, String> optionalScope) {
        return OauthConnect(scopeList, redirectUri, optionalScope, "");
    }

    /**
     * 生成授权链接,获取授权码
     *
     * @param scopeList     应用授权作用域
     * @param redirectUri   授权成功后的回调地址，必须以http/https开头。域名必须对应申请应用时填写的域名，如不清楚请联系应用申请人。
     * @param optionalScope 应用授权可选作用域,多个授权作用域以英文逗号（,）分隔，每一个授权作用域后需要加上一个是否默认勾选的参数，1为默认勾选，0为默认不勾选
     * @param state         用于保持请求和回调的状态
     * @return
     */
    public String OauthConnect(List<DouYingScope> scopeList, String redirectUri, Map<DouYingScope, String> optionalScope, String state) {
        return OauthConnect.New().
                setClient_key(clientKey).
                setScopes(scopeList).
                setRedirectUri(redirectUri).
                setOptionalScope(optionalScope).
                setState(state).
                execute();
    }

    private OauthAccessToken OauthAccessToken(String code) {
        OauthAccessToken oauthAccessToken = OauthAccessToken.New().
                setClient_key(clientKey).
                setClient_secret(clientSecret).
                setCode(code).
                execute();
        OauthAccessToken.OauthAccessTokenResponse oauthAccessTokenResponse = oauthAccessToken.convert();
        this.access_token = oauthAccessTokenResponse.getAccess_token();
        this.open_id = oauthAccessTokenResponse.getOpen_id();
        this.refresh_token = oauthAccessTokenResponse.getRefresh_token();
        return oauthAccessToken;
    }

    /**
     * 获取access_token
     *
     * @param code 授权码
     * @return
     */
    public String OauthAccessTokenStr(String code) {
        return OauthAccessToken(code).
                getResponse();
    }


    /**
     * 获取access_token
     *
     * @param code 授权码
     * @return
     */
    public OauthAccessToken.OauthAccessTokenResponse OauthAccessTokenObj(String code) {
        return OauthAccessToken(code).
                convert();
    }

    private OauthRenewRefreshToken OauthRenewRefreshToken() {
        OauthRenewRefreshToken oauthRenewRefreshToken = OauthRenewRefreshToken.New().
                setClient_key(clientKey).
                setRefresh_token(refresh_token).
                execute();
        this.refresh_token = oauthRenewRefreshToken.convert().getRefresh_token();
        return oauthRenewRefreshToken;
    }

    /**
     * 刷新refresh_token
     *
     * @return
     */
    public String OauthRenewRefreshTokenStr() {
        return OauthRenewRefreshToken().getResponse();
    }

    /**
     * 刷新refresh_token
     *
     * @return
     */
    public OauthRenewRefreshToken.OauthRenewRefreshTokenResponse OauthRenewRefreshTokenObj() {
        return OauthRenewRefreshToken().convert();
    }

    private OauthClientToken OauthClientToken() {
        return OauthClientToken.New().setClient_key(clientKey).setClient_secret(clientSecret).execute();
    }

    /**
     * 生成client_token
     *
     * @return
     */
    public String OauthClientTokenStr() {
        return OauthClientToken().getResponse();
    }

    /**
     * 生成client_token
     *
     * @return
     */
    public OauthClientToken.OauthClientTokenResponse OauthClientTokenObj() {
        return OauthClientToken().convert();
    }

    private OauthRefreshToken OauthRefreshToken() {
        OauthRefreshToken oauthRefreshToken = OauthRefreshToken.New().
                setClient_key(clientKey).
                setRefresh_token(refresh_token).
                execute();
        OauthAccessToken.OauthAccessTokenResponse oauthAccessTokenResponse = oauthRefreshToken.convert();
        this.access_token = oauthAccessTokenResponse.getAccess_token();
        this.open_id = oauthAccessTokenResponse.getOpen_id();
        this.refresh_token = oauthAccessTokenResponse.getRefresh_token();
        return oauthRefreshToken;
    }

    /**
     * 刷新access_token
     *
     * @return
     */
    public String OauthRefreshTokenStr() {
        return OauthRefreshToken().getResponse();
    }

    /**
     * 刷新access_token
     *
     * @return
     */
    public OauthAccessToken.OauthAccessTokenResponse OauthRefreshTokenObj() {
        return OauthRefreshToken().convert();
    }

    private OauthUserinfo OauthUserinfo() {
        OauthUserinfo oauthUserinfo = OauthUserinfo.New().setAccess_token(access_token).setOpen_id(open_id).execute();
        OauthUserinfo.OauthUserinfoResponse oauthUserinfoResp = oauthUserinfo.convert();
        this.open_id = oauthUserinfoResp.getOpen_id();
        return OauthUserinfo.New().setAccess_token(access_token).setOpen_id(open_id).execute();
    }

    /**
     * 获取用户信息
     *
     * @return
     */
    public String OauthUserinfoStr() {
        return OauthUserinfo().getResponse();
    }

    /**
     * 获取用户信息
     *
     * @return
     */
    public OauthUserinfo.OauthUserinfoResponse OauthUserinfoObj() {
        return OauthUserinfo().convert();
    }

    public String DecryptMobile(String encrypt_mobile) {
        try {
            String clientSecret = this.clientSecret;
            String encryptedMobile = encrypt_mobile;
            byte[] clientSecretBytes = clientSecret.getBytes();
            SecretKey secretKey = new SecretKeySpec(clientSecretBytes, 0, clientSecretBytes.length, "AES");
            byte[] iv = Arrays.copyOfRange(clientSecretBytes, 0, 16);
            IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);
            String algorithm = "AES/CBC/PKCS5Padding";
            Cipher cipher = Cipher.getInstance(algorithm);
            cipher.init(Cipher.DECRYPT_MODE, secretKey, ivParameterSpec);
            byte[] plainText = cipher.doFinal(Base64.getDecoder().decode(encryptedMobile));
            return new String(plainText);
        } catch (Exception e) {
            log.debug("解密手机号异常：{}", e.getMessage());
        }
        return "";
    }

    private FansList FansList(int cursor, int count) {
        return FansList.New().
                setOpen_id(open_id).
                setAccess_token(access_token).
                setCount(count).
                setCursor(cursor).execute();
    }

    /**
     * 粉丝列表
     *
     * @param cursor 每页数量
     * @param count  调用/oauth/access_token/生成的token，此token需要用户授权。
     * @return
     */
    public String FansListStr(int cursor, int count) {
        return FansList(cursor, count).getResponse();
    }

    /**
     * 粉丝列表
     *
     * @param cursor 每页数量
     * @param count  调用/oauth/access_token/生成的token，此token需要用户授权。
     * @return
     */
    public List<FansList.FansListResponse> FansListObj(int cursor, int count) {
        return FansList(cursor, count).convert();
    }

    private FollowingList FollowingList(int cursor, int count) {
        return FollowingList.New().
                setOpen_id(open_id).
                setAccess_token(access_token).
                setCount(count).
                setCursor(cursor).execute();
    }

    /**
     * 关注列表
     *
     * @param cursor 每页数量
     * @param count  调用/oauth/access_token/生成的token，此token需要用户授权。
     * @return
     */
    public String FollowingListStr(int cursor, int count) {
        return FollowingList(cursor, count).getResponse();
    }

    /**
     * 关注列表
     *
     * @param cursor 每页数量
     * @param count  调用/oauth/access_token/生成的token，此token需要用户授权。
     * @return
     */
    public List<FansList.FansListResponse> FollowingListObj(int cursor, int count) {
        return FollowingList(cursor, count).convert();
    }

    private FansCheck FansCheck(String follower_open_id, String access_token) {
        return FansCheck.New().
                setOpen_id(open_id).
                setFollower_open_id(follower_open_id).
                setAccess_token(access_token).
                execute();
    }

    /**
     * 粉丝判断
     *
     * @param follower_open_id
     * @param access_token     调用/oauth/access_token/生成的token，此token需要用户授权。
     * @return
     */
    public String FansCheckStr(String follower_open_id, String access_token) {
        return FansCheck(follower_open_id, access_token).getResponse();
    }

    /**
     * 粉丝判断
     *
     * @param follower_open_id
     * @param access_token     调用/oauth/access_token/生成的token，此token需要用户授权。
     * @return
     */
    public FansCheck.FansCheckResponse FansCheckObj(String follower_open_id, String access_token) {
        return FansCheck(follower_open_id, access_token).convert();
    }

    private VideoUpload VideoUpload(String video) {
        return VideoUpload.New().setAccess_token(access_token).setOpen_id(open_id).setVideo(FileUtil.file(video)).execute();
    }

    /**
     * 上传视频
     *
     * @param video 待上传视频文件
     * @return
     */
    public String VideoUploadStr(String video) {
        return VideoUpload(video).getResponse();
    }

    /**
     * 上传视频
     *
     * @param video 待上传视频文件
     * @return
     */
    public VideoUpload.VideoUploadResponse VideoUploadObj(String video) {
        return VideoUpload(video).convert();
    }

    private VideoPartUploadInit VideoPartUploadInit() {
        return VideoPartUploadInit.New().setAccess_token(access_token).setOpen_id(open_id).execute();
    }

    /**
     * 初始化分片上传
     *
     * @return
     */
    public String VideoPartUploadInitStr() {
        return VideoPartUploadInit().getResponse();
    }

    /**
     * 初始化分片上传
     *
     * @return
     */
    public VideoPartUploadInit.VideoPartUploadInitResponse VideoPartUploadInitObj() {
        return VideoPartUploadInit().convert();
    }

    private VideoPartUpload VideoPartUpload(String upload_id, int part_number, String video) {
        return VideoPartUpload.New().
                setAccess_token(access_token).
                setOpen_id(open_id).
                setPart_number(part_number).
                setUpload_id(upload_id).setVideo(FileUtil.file(video)).execute();
    }

    /**
     * 上传视频分片到文件服务器
     *
     * @param upload_id   分片上传的标记。有限时间为2小时。
     * @param part_number 表示该分片在整个视频内的相对位置，从1开始（1即表示第一段视频分片）。
     * @param video       视频分片，建议20MB。但不能小于5MB。
     * @return
     */
    public String VideoPartUploadStr(String upload_id, int part_number, String video) {
        return VideoPartUpload(upload_id, part_number, video).getResponse();
    }

    private VideoUploadPartComplete VideoUploadPartComplete(String upload_id) {
        return VideoUploadPartComplete.New().setAccess_token(access_token).setOpen_id(open_id).setUpload_id(upload_id).execute();
    }

    /**
     * 完成分片上传
     *
     * @param upload_id 分片上传的标记。有限时间为2小时。
     * @return
     */
    public String VideoUploadPartCompleteStr(String upload_id) {
        return VideoUploadPartComplete(upload_id).getResponse();
    }

    private VideoCreate VideoCreate(String video_id, String text) {
        return VideoCreate.New().setOpen_id(open_id).setAccess_token(access_token).setVideo_id(video_id).setText(text).execute();
    }

    /**
     * 创建抖音视频
     *
     * @param video_id video_id, 通过/video/upload/接口得到。注意每次调用/video/create/都要调用/video/upload/生成新的video_id。
     * @param text     视频标题， 可以带话题,@用户。注意：话题审核依旧遵循抖音的审核逻辑，强烈建议第三方谨慎拟定话题名称，避免强导流行为。
     * @return
     */
    public String VideoCreateStr(String video_id, String text) {
        return VideoCreate(video_id, text).getResponse();
    }

    /**
     * 创建抖音视频
     *
     * @param video_id video_id, 通过/video/upload/接口得到。注意每次调用/video/create/都要调用/video/upload/生成新的video_id。
     * @param text     视频标题， 可以带话题,@用户。注意：话题审核依旧遵循抖音的审核逻辑，强烈建议第三方谨慎拟定话题名称，避免强导流行为。
     * @return
     */
    public VideoCreate.VideoCreateResponse VideoCreateObj(String video_id, String text) {
        return VideoCreate(video_id, text).convert();
    }

    private ImageUpload ImageUpload(String image) {
        return ImageUpload.New().setAccess_token(access_token).setOpen_id(open_id).setImage(FileUtil.file(image)).execute();
    }

    /**
     * 上传图片到文件服务器
     *
     * @param image 图片
     * @return
     */
    public String ImageUploadStr(String image) {
        return ImageUpload(image).getResponse();
    }

    /**
     * 上传图片到文件服务器
     *
     * @param image 图片
     * @return
     */
    public ImageUpload.ImageUploadResponse ImageUploadObj(String image) {
        return ImageUpload(image).convert();
    }

    private ImageCreate ImageCreate(String image_id, String text) {
        return ImageCreate.New().setOpen_id(open_id).setAccess_token(access_token).setImage_id(image_id).setText(text).execute();
    }

    /**
     * 发布图片
     *
     * @param image_id 通过/image/upload/接口得到。
     * @param text     标题，可以带话题。 如title1#话题1 #话题2 注意：话题审核依旧遵循抖音的审核逻辑，强烈建议第三方谨慎拟定话题名称，避免强导流行为。
     * @return
     */
    public String ImageCreateStr(String image_id, String text) {
        return ImageCreate(image_id, text).getResponse();
    }

    /**
     * 发布图片
     *
     * @param image_id 通过/image/upload/接口得到。
     * @param text     标题，可以带话题。 如title1#话题1 #话题2 注意：话题审核依旧遵循抖音的审核逻辑，强烈建议第三方谨慎拟定话题名称，避免强导流行为。
     * @return
     */
    public ImageCreate.ImageCreateResponse ImageCreateObj(String image_id, String text) {
        return ImageCreate(image_id, text).convert();
    }

    private VideoList VideoList(int cursor, int count) {
        return VideoList.New().setAccess_token(access_token).setOpen_id(open_id).setCount(count).setCursor(cursor).execute();
    }

    /**
     * 查询授权账号视频数据
     *
     * @param cursor 分页游标, 第一页请求cursor是0, response中会返回下一页请求用到的cursor, 同时response还会返回has_more来表明是否有更多的数据。
     * @param count  每页数量
     * @return
     */
    public String VideoListStr(int cursor, int count) {
        return VideoList(cursor, count).getResponse();
    }


    public String getClientKey() {
        return clientKey;
    }

    public void setClientKey(String clientKey) {
        this.clientKey = clientKey;
    }

    public String getClientSecret() {
        return clientSecret;
    }

    public void setClientSecret(String clientSecret) {
        this.clientSecret = clientSecret;
    }

    public String getAccess_token() {
        return access_token;
    }

    public void setAccess_token(String access_token) {
        this.access_token = access_token;
    }

    public String getOpen_id() {
        return open_id;
    }

    public void setOpen_id(String open_id) {
        this.open_id = open_id;
    }

    public String getRefresh_token() {
        return refresh_token;
    }

    public void setRefresh_token(String refresh_token) {
        this.refresh_token = refresh_token;
    }
}
